#pragma once

#include<queue>
#include<mutex>
#include<pthread.h>
#include"LockGuard.hpp"

namespace wbj
{
#define DEF_SIZE 10
    
    template<class T>
    class BlockQueue
    {
    public:
        BlockQueue(size_t cap=DEF_SIZE)
            :_cap(cap)
            {
                //初始化锁和条件变量
                pthread_mutex_init(&_mtx,nullptr);
                pthread_cond_init(&_pro_cond,nullptr);
                pthread_cond_init(&_con_cond,nullptr);
            }

            ~BlockQueue()
            {
                pthread_mutex_destroy(&_mtx);
                pthread_cond_destroy(&_pro_cond);
                pthread_cond_destroy(&_con_cond);
            }

            void Push(const T& inDate)
            {
                //上锁
                LockGuard lock(&_mtx);

                //循环判断条件是否满足
                while(IsFull)
                {
                    pthread_cond_wait(&_pro_cond,&_mtx);
                }

                _queue.push(inDate);

                pthread_cond_signal(&con_cond);
            }

            void Pop(T* outDate)
            {
                LockGuard lock(&_con_cond);

                while(IsEmpty())
                {
                    pthread_mutex_wait(&_con_cond,&_mtx);
                }

                *outDate=_queue.front();
                _queue.pop();

                pthread_cond_signal(&_pro_cond);
            }
    private:
    bool IsFull()
    {
        return _queue.size()==_cap;
    }

    bool IsEmpty()
    {
        return _queue.empty();
    }
    private:
        std::queue<T> _queue;
        size_t _cap;//阻塞队列的容量
        pthread_mutex_t _mtx;//互斥锁
        pthread_cond_t _pro_cond;//生产者条件变量
        pthread_cond_t _con_cond;//消费者条件变量
    }
}